package cn.wolfcode.web.controller;

import cn.wolfcode.common.domain.UserInfo;
import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.common.web.anno.RequireLogin;
import cn.wolfcode.domain.OrderInfo;
import cn.wolfcode.domain.SeckillProduct;
import cn.wolfcode.mapper.SeckillProductMapper;
import cn.wolfcode.mq.MQConstant;
import cn.wolfcode.mq.OrderMessage;
import cn.wolfcode.redis.CommonRedisKey;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.util.DateUtil;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.ConcurrentHashMap;


@RestController
@RequestMapping("/order")
@Slf4j
public class OrderInfoController {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private IOrderInfoService orderInfoService;

    //本地标识（放在方法区）：根据redis中预库存，作为访问redis的开关，进而也是service的开关
    public static final ConcurrentHashMap<Long,Boolean> seckillproductIsSelloutMap=new ConcurrentHashMap<>();

    //秒杀之下单功能：order/doSeckill
    @RequestMapping("/doSeckill")
    @RequireLogin
    public Result<String> doSeckill(HttpServletRequest request,Long seckillId, Long time){
        /**
         *继续进行优化：这时请求全会打入redis中，为了减少redia访问的压力.
         * 本地标识ConcurrentHashMap,用来保存一个标识<seckillId：Boolean>,用来表示预库存如果为0说明redis不能再接收访问了
         */
//        seckillproductIsSelloutMap.put(seckillId,false);
        if(seckillproductIsSelloutMap.get(seckillId)==null){
            seckillproductIsSelloutMap.put(seckillId,false);
        }
        Boolean flag = seckillproductIsSelloutMap.get(seckillId);
        if(flag){//true,说明库存为<0了;不往下执行（访问redis）了
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }
        /**
         * 进行优化：预库存
         * 通过redis设置一个预库存解决频繁访问mysql数据库（redis控制访问service秒杀业务的访问量）
         *          hash类型：  time <seckillid  库存数量>
         */
        Object stringPrecount = redisTemplate.opsForHash()
                .increment(SeckillRedisKey.SECKILL_STOCK_COUNT_HASH.getRealKey(time.toString()), seckillId + "",-1);
        Integer preCount = JSON.parseObject(stringPrecount.toString(), Integer.class);
        if (preCount<=0){//预库存<=0,不玩下执行(访问service)了
            seckillproductIsSelloutMap.put(seckillId,true);//预库存<0则，修改本地标识为true
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }

        String token = request.getHeader("token");
        String stringUserInfo = redisTemplate.opsForValue().get(CommonRedisKey.USER_TOKEN.getRealKey(token));
        UserInfo userInfo = JSON.parseObject(stringUserInfo, UserInfo.class);
        Long phone=userInfo.getPhone();//可以代表着此用户
        /**
         * 校验参数  ：和之前一样
         */
        if(!StringUtils.hasText(String.valueOf(seckillId)) || !StringUtils.hasText(String.valueOf(time))){
            throw new BusinessException(SeckillCodeMsg.INTERGRAL_SERVER_invalidate);
        }
        /**
         * 是否在活动期内：注意当前抢购商品的时间是否在活动开始(开场时间)和结束时间+2h
         */
        SeckillProduct seckillProduct = seckillProductService.querySeckillProductBytimeAndseckillId(time, seckillId);
//        boolean legalTime = DateUtil.isLegalTime(seckillProduct.getStartDate(), seckillProduct.getTime());
//        if(!legalTime){
//            throw new BusinessException(SeckillCodeMsg.CANCEL_ORDER_ERROR);
//        }
        /**
         *  真实库存是否足够
         */
        if(seckillProduct.getStockCount()<=0){
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }
        /**
         * 判断是否重复下单：如果使用hash结构  time   <<phone:seckillId，seckillId>>（判断该用户是否在某个场次已经下单该商品）
         */
        String hengji=phone+":"+seckillId;
        Boolean member = redisTemplate.opsForSet().isMember(SeckillRedisKey.SECKILL_ORDER_SET.getRealKey(time.toString()), hengji);
        if(member){
            throw new BusinessException(SeckillCodeMsg.REPEAT_SECKILL);
        }
        //秒杀逻辑
//        String orderNo=seckillProductService.doSeckill(seckillId,time,phone);
        OrderMessage orderMessage = new OrderMessage();//用这个类型对象封装我们所需的数据
        orderMessage.setTime(time.intValue());
        orderMessage.setSeckillId(seckillId);
        orderMessage.setUserPhone(phone);
        orderMessage.setToken(token);
        rocketMQTemplate.sendOneWay(MQConstant.ORDER_PEDDING_TOPIC,orderMessage);
        return Result.success("正在抢购中，请稍等。。。");
    }
    //查询订单：order/find?orderNo=1466404626256363520
    @RequestMapping("/find")
    public Result<OrderInfo> getOrderInfo(HttpServletRequest request,String orderNo ){
        String token = request.getHeader("token");
        OrderInfo orderInfo=orderInfoService.find(token,orderNo);
        return Result.success(orderInfo);
    }
}
